import flask
from flask_login import LoginManager, UserMixin, current_user, login_required, login_user

import os
import re
import datetime
import threading

try:
    from config_manager import ConfigManager
except ModuleNotFoundError:
    import sys

    sys.path.append(".")
    from config_manager import ConfigManager

cfg_mgr = ConfigManager()
app = flask.Flask(__name__)

PasswordLock = threading.RLock()
SignInLock = threading.RLock()
SIGN_IN_CODE = []


# 设置表单交互密钥
def get_secret_key():
    with open(cfg_mgr.path_formate(cfg_mgr["secret_key_path"])) as fp:
        secret_key = fp.read().strip()
    return secret_key


app.secret_key = get_secret_key()

login_manager = LoginManager()  # 实例化登录管理对象
login_manager.init_app(app)  # 初始化应用
login_manager.login_view = 'login'  # 设置用户登录视图函数 endpoint

class_note_files = cfg_mgr["class_notes"]


class User(UserMixin):
    """用户类"""

    def __init__(self, user_id):
        self.username = user_id

    def verify_password(self, password):
        """密码验证"""
        return verify_password(self.username, password)

    def get_id(self):
        """获取用户ID"""
        return self.username


def verify_password(username, password):
    """密码验证"""
    ret = False
    PasswordLock.acquire()
    try:
        data = cfg_mgr.yaml_load(cfg_mgr["password_path"])
        print(">>", username, "Trying sign in.")
        ret = data.get(username) == password
    except Exception as err:
        print(repr(err))
    finally:
        PasswordLock.release()
        return ret


@app.route("/")
@app.route("/guild")
def welcome():
    return flask.render_template("guide.html", notes=class_note_files)


@app.route("/class/<file_name>")
def get_class_html(file_name):
    print(file_name)
    if file_name in class_note_files:
        return app.send_static_file(file_name)
    else:
        flask.abort(404)


@app.route("/static/<file_name>")
def static_file(file_name: str):
    if re.match(r"^bx_\d+_.+", file_name):
        path = "./static/" + file_name
        if os.path.isfile(path):
            file_type = file_name.rsplit(".", 1)[-1]
            if file_type == "pdf":
                resp = flask.send_file(path)
            else:
                with open(path, "rb") as fp:
                    img = fp.read()
                resp = flask.Response(img, mimetype="image/%s" % file_type)
            return resp
    flask.abort(404)


@app.route("/media/<file_name>")
def media_file(file_name):
    try:
        with open("media/" + file_name, "r") as fp:
            text = fp.read()
    except FileNotFoundError:
        flask.abort(404)
    else:
        text_type = file_name.rsplit(".", 1)[-1]
        return flask.Response(text, mimetype="text/%s" % text_type)


@app.route("/SignIn/<code>")
@login_required
def sign_in(code):
    """
    签到界面
    """
    msg = "内部错误, 请重试"
    try:
        SignInLock.acquire(timeout=1)
    except TimeoutError:
        msg = "Time Out Error! Try again."
    try:
        if msg != "Time Out Error! Try again." and code in SIGN_IN_CODE:
            write_sign_in_file = False
            data = cfg_mgr.yaml_load(cfg_mgr["sign_in_log"])
            if not isinstance(data, dict):
                write_sign_in_file = True
                data = {}
            key = str(datetime.datetime.now().date())
            log = data.setdefault(key, [])
            user_name = current_user.username
            print("Sign In", user_name)
            if user_name is log:
                msg = "已签到, 请勿重复扫码"
            else:
                log.append(user_name)
                write_sign_in_file = True
                msg = None
            if write_sign_in_file:
                cfg_mgr.yaml_dump(data, cfg_mgr["sign_in_log"])
        else:
            msg = "二维码错误"
    finally:
        SignInLock.release()
    if not msg:
        return flask.render_template('code.html', msg='成功签到')
    else:
        return flask.render_template('code.html', msg=msg)


@app.route("/login", methods=('GET', 'POST'))
def login():
    """

    """
    if current_user.is_authenticated:
        return flask.redirect("./guild", code=302)

    if flask.request.method == "GET":
        return flask.render_template("login.html")
    else:
        username = flask.request.form.get("user")
        try:
            a, b = username.split(".")
        except ValueError:
            return flask.render_template("login.html", msg="登陆失败")

        username = "%s.%s" % (a.capitalize(), b.capitalize())

        print(username)

        token = flask.request.form.get("pwd")

        if not verify_password(username, token):
            return flask.render_template("login.html", msg="登陆失败")

        user = User(username)
        login_user(user)
        print("sign in")
        next_page = flask.request.args.get('next')
        if not next_page:
            return flask.redirect("./guild", code=302)
        return flask.redirect(next_page)


@login_manager.user_loader  # 定义获取登录用户的方法
def load_user(user_id):
    print("load-user Run")
    PasswordLock.acquire()
    ret = None
    try:
        data = cfg_mgr.yaml_load(cfg_mgr["password_path"])
        if data and user_id in data:
            ret = User(user_id)
    finally:
        PasswordLock.release()
    return ret


if __name__ == "__main__":
    from desktop_app_ui.sign_in_code_app import tk, SignInCodeApp
    from gevent import pywsgi


    class SignInCodeFrame(SignInCodeApp):
        def qr_code_update_callback(self, data):
            try:
                SignInLock.acquire()
                SIGN_IN_CODE.clear()
                SIGN_IN_CODE.append(data.rsplit("/")[-1])
                print(SIGN_IN_CODE)
            finally:
                SignInLock.release()


    def run_app():
        root = tk.Tk()
        root.title("Sign In Code")
        win = SignInCodeFrame(root)
        win.pack(expand=1)
        win.mainloop()


    print("ready tk threading")
    win_thr = threading.Thread(target=run_app)
    win_thr.start()

    # start server with WSGI
    server = pywsgi.WSGIServer(("0.0.0.0", 5001), app)
    server.serve_forever()

    # wait ui quit
    win_thr.join()
